package com.gzc.just.play.last.war.common.share.persistence;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * Database configuration
 * Configure data source, JPA and transaction management
 * 
 * 注意：此配置类用于生产环境（MySQL/PostgreSQL等）
 * dev-all-in-one模式使用SQLiteDataSourceConfig
 */
@Configuration("commonDatabaseConfig")
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.gzc.just.play.last.war", 
                       repositoryBaseClass = BaseRepositoryImpl.class)
@org.springframework.context.annotation.Profile("!dev-all-in-one")
public class DatabaseConfig {

    private static final Logger log = LoggerFactory.getLogger(DatabaseConfig.class);

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;

    /**
     * Configure primary data source
     */
    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(url);
        config.setUsername(username);
        config.setPassword(password);
        config.setDriverClassName(driverClassName);
        
        // Connection pool configuration
        config.setMinimumIdle(5);
        config.setMaximumPoolSize(50);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);
        
        // Performance optimization configuration
        config.setAutoCommit(false);
        config.setConnectionTestQuery("SELECT 1");
        config.setValidationTimeout(5000);
        
        // Connection name (for monitoring)
        config.setPoolName("GameServerHikariPool");
        
        // Enable JMX monitoring
        config.setRegisterMbeans(true);
        
        // Enable connection leak detection
        config.setLeakDetectionThreshold(60000);
        
        log.info("Configured HikariCP with URL: {}", url);
        return new HikariDataSource(config);
    }

    /**
     * Configure JPA entity manager factory
     */
    @Primary
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        
        // Set packages to scan
        em.setPackagesToScan("com.gzc.just.play.last.war");
        
        // Set JPA vendor adapter
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        
        // Set JPA properties
        Properties properties = new Properties();
        
        // Basic configuration
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        properties.setProperty("hibernate.show_sql", "false");
        properties.setProperty("hibernate.format_sql", "true");
        properties.setProperty("hibernate.use_sql_comments", "true");
        
        // Connection configuration
        properties.setProperty("hibernate.connection.provider_disables_autocommit", "true");
        properties.setProperty("hibernate.jdbc.batch_size", "50");
        properties.setProperty("hibernate.order_inserts", "true");
        properties.setProperty("hibernate.order_updates", "true");
        properties.setProperty("hibernate.jdbc.batch_versioned_data", "true");
        
        // Second-level cache configuration
        properties.setProperty("hibernate.cache.use_second_level_cache", "true");
        properties.setProperty("hibernate.cache.use_query_cache", "false");
        properties.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.jcache.JCacheRegionFactory");
        properties.setProperty("hibernate.javax.cache.provider", "org.ehcache.jsr107.EhcacheCachingProvider");
        properties.setProperty("hibernate.javax.cache.uri", "classpath:ehcache.xml");
        
        // Statistics configuration
        properties.setProperty("hibernate.generate_statistics", "true");
        properties.setProperty("hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS", "100");
        
        // Naming strategy
        properties.setProperty("hibernate.physical_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
        properties.setProperty("hibernate.implicit_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
        
        em.setJpaProperties(properties);
        
        log.info("Configured JPA EntityManager Factory");
        return em;
    }

    /**
     * Configure transaction manager
     */
    @Primary
    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        
        // Configure transaction properties
        Properties transactionProperties = new Properties();
        transactionProperties.setProperty("defaultTimeout", "30");
        transactionProperties.setProperty("rollbackFor", "java.lang.Exception");
        
        transactionManager.setJpaDialect(new org.springframework.orm.jpa.vendor.HibernateJpaDialect());
        
        log.info("Configured JPA Transaction Manager");
        return transactionManager;
    }
}